﻿using System;
using System.Reflection;
using System.Reflection.Emit;

namespace Aeon.Emulator.Decoding.Recompiler.StringCompilers
{
    /// <summary>
    /// Generates IL for emulating an OUTS instruction.
    /// </summary>
    internal sealed class OutsCompiler : StringBase
    {
        private static readonly MethodInfo WritePortByte = typeof(VirtualMachine).GetMethod("WritePortByte", BindingFlags.Instance | BindingFlags.NonPublic);
        private static readonly MethodInfo WritePortWord = typeof(VirtualMachine).GetMethod("WritePortWord", BindingFlags.Instance | BindingFlags.NonPublic);

        /// <summary>
        /// Initializes a new instance of the OutsCompiler class.
        /// </summary>
        /// <param name="registers">Associated register expression generator.</param>
        public OutsCompiler(RegisterExpressions registers)
            : base(registers, false)
        {
        }

        /// <summary>
        /// Generates the IL for one iteration of the instruction.
        /// </summary>
        protected override void GenerateIteration()
        {
            LoadVirtualMachine();
            GenerateDX();
            this.IL.Emit(OpCodes.Conv_U4);
            GenerateDS_SI();

            if(this.OperandSize == 32)
            {
                this.IL.Emit(OpCodes.Conv_U2);
                this.IL.Emit(OpCodes.Call, WritePortWord);
            }
            else if(this.OperandSize == 16)
                this.IL.Emit(OpCodes.Call, WritePortWord);
            else if(this.OperandSize == 8)
                this.IL.Emit(OpCodes.Call, WritePortByte);
            else
                throw new InvalidOperationException();

            IncrementSI();
        }
    }
}
